/*
 * Dcm_UDS0x23.c
 *
 *  Created on: 2018-8-6
 *      Author: tao.yu
 */

#include "UDS.h"


/****************************************************************
     UDS: ReadMemoryByAddress (23 hex) service
 ***************************************************************/
#if (STD_ON == DCM_UDS_SERVICE0X23_ENABLED)
/******************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
static FUNC(Std_ReturnType, DCM_CODE)Dcm_0x23MemoryReadSecurityCheck(
        uint8 MemoryIdInfoIndex,
        uint8 MemoryRangeInfoIndex)
{
    uint8 index;
    Std_ReturnType ret = E_NOT_OK;
    uint8 SecNum;
    P2CONST(Dcm_DspReadMemoryRangeInfoType, AUTOMATIC, DCM_VAR_NOINIT)
     pDcmDspReadMemoryRangeInfo;

    pDcmDspReadMemoryRangeInfo =
            &(Dcm_DspCfg.pDcmDspMemory->DcmDspMemoryIdInfo[MemoryIdInfoIndex].
                    DcmDspReadMemoryRangeInfo[MemoryRangeInfoIndex]);
    SecNum = pDcmDspReadMemoryRangeInfo->DcmDspReadMemorySecurityLevelRefNum;
    if (SecNum != 0u)
    {
        /*[SWS_Dcm_00494] */
        for (index = 0; (index < SecNum); index++)
        {
            if (Dcm_MkCtrl.Dcm_ActiveSec ==
                pDcmDspReadMemoryRangeInfo->pDcmDspReadMemorySecurityLevelRow[index])
            {
                ret = E_OK;
            }
        }
    }
    else
    {
         ret = E_OK;
    }

    return ret;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"

/******************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
static FUNC(Std_ReturnType, DCM_CODE)Dcm_0x23ReadMemoryRangeCheck(
        uint32 MemoryAddress,
        uint32 Memorysize,
        P2VAR(uint8, AUTOMATIC, AUTOMATIC)MemoryIdInfoIndex,
        P2VAR(uint8, AUTOMATIC, AUTOMATIC)MemoryRangeInfoIndex,
        P2VAR(uint8, AUTOMATIC, AUTOMATIC)MemoryAddressMatchNum)
{
    uint8 IdInfoIndex;
    uint8 RangeInfoIndex;
    Std_ReturnType ret = E_NOT_OK;
    P2CONST(Dcm_DspReadMemoryRangeInfoType, AUTOMATIC, DCM_VAR_NOINIT)
     pDcmDspReadMemoryRangeInfo;
    P2CONST(Dcm_DspMemoryIdInfoType, AUTOMATIC, DCM_VAR_NOINIT)
     pDcmDspMemoryIdInfo;

    for(IdInfoIndex = 0u;
            IdInfoIndex < Dcm_DspCfg.pDcmDspMemory->DcmDspMemoryIdInfoNum;
            IdInfoIndex++)
    {
        pDcmDspMemoryIdInfo =
             &(Dcm_DspCfg.pDcmDspMemory->DcmDspMemoryIdInfo[IdInfoIndex]);
        if (pDcmDspMemoryIdInfo != NULL_PTR)
        {
            for(RangeInfoIndex = 0;
                RangeInfoIndex < pDcmDspMemoryIdInfo->DcmDspReadMemoryRangeInfoNum;
                RangeInfoIndex++)
            {
                pDcmDspReadMemoryRangeInfo =
                  &(pDcmDspMemoryIdInfo->DcmDspReadMemoryRangeInfo[RangeInfoIndex]);
                if (pDcmDspReadMemoryRangeInfo != NULL_PTR)
                {
                    if ((pDcmDspReadMemoryRangeInfo->DcmDspReadMemoryRangeLow
                            <= MemoryAddress)
                        && (pDcmDspReadMemoryRangeInfo->DcmDspReadMemoryRangeHigh
                                >= (MemoryAddress + Memorysize - 1u)))
                    {
                        *MemoryIdInfoIndex = IdInfoIndex;
                        *MemoryRangeInfoIndex = RangeInfoIndex;
                        *MemoryAddressMatchNum += 1u;
                        ret = E_OK;
                    }
                }
            }
        }
    }
    return ret;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"

/******************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
static FUNC(Std_ReturnType, DCM_CODE)Dcm_Uds0x23ServiceAddressAndLengthFormatIdentifierCheck(
                const uint8 addressAndLengthFormatIdentifier)
{
    Std_ReturnType ret = E_NOT_OK;
    uint8 iloop;

    for (iloop = 0;
            (iloop < Dcm_DspCfg.pDcmDspMemory->DcmDspAddressAndLengthFormatIdentifierNum)
                    && (ret == E_NOT_OK);
            iloop++)
    {
        if(addressAndLengthFormatIdentifier ==
          Dcm_DspCfg.pDcmDspMemory->DcmDspAddressAndLengthFormatIdentifier[iloop].
          DcmDspSupportedAddressAndLengthFormatIdentifier)
        {
            ret = E_OK;
        }
    }
    return ret;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"

/***************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
static FUNC(Std_ReturnType, DCM_CODE)Dcm_Uds0x23ServiceConditionCheck(
        uint8 ProtocolCtrlId,
        uint8 MsgCtrlId)
{
    Std_ReturnType ret;

    /*************************************************/
#if(STD_ON == DCM_SESSION_FUNC_ENABLED)
    /*session check,check whether the current
     * session supports the request service*/
    ret = DsdInternal_SesCheck(ProtocolCtrlId,
            SID_READ_DATA_BY_MEMORYADDRESS);
    if(E_NOT_OK == ret)
    {
        /****@req DCM-FUNR-073[DCM211]****/
        /*the current session does not support
         * the request service,send NRC = 0x7F*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_SERVICENOTSUPPORTEDINACTIVESESSION);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
#endif

    /*************************************************/
#if(STD_ON == DCM_SECURITY_FUNC_ENABLED)
    /*security check,check whether the current security supports the request service*/
    ret = DsdInternal_SecurityCheck(ProtocolCtrlId,
            SID_READ_DATA_BY_MEMORYADDRESS);
    if(E_NOT_OK == ret)
    {
        /****@req DCM-FUNR-074[DCM217]****/
        /*the current security does not support the request service,send NRC = 0x33*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_SECURITYACCESSDENIED);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
#endif
    /*min-length check*/
    if (DCM_UDS0X23_REQ_DATA_MINLENGTH > Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen)
    {
        /*the min length of message is not correct,send NRC 0x13*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
    return E_OK;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"


/*******************************/
#define DCM_START_SEC_CODE
#include "Dcm_MemMap.h"
FUNC(Std_ReturnType, DCM_CODE)Dcm_UDS0x23(
        Dcm_OpStatusType OpStatus,
        uint8  ProtocolCtrlId,
        P2VAR(Dcm_NegativeResponseCodeType,AUTOMATIC,DCM_VAR) ErrorCode)
{
    uint8  MsgCtrlId;
    Std_ReturnType ret;
    uint8  AddressAndLengthFormatIdentifier;
    uint32 MemoryAddress = 0u;
    uint32 Memorysize = 0u;
    uint8  TxChannelCtrlIndex;
    uint8  TxChannelCfgIndex;
    uint16 Offset;
    uint8* DCM_MemoryData;
    uint8 MemoryIdInfoIndex = 0u;
    uint8 MemoryRangeInfoIndex = 0u;
    uint8 MemoryAddressSize;
    uint8 MemoryLengthSize;
    uint8 index;
    uint8 MemoryAddressMatchNum = 0;
    uint8 MemoryIdentifier;

    /*************************************************/
    /*if the required protocol is configured,get the index of runtime datum*/
    MsgCtrlId =  Dcm_ProtocolCtrl[ProtocolCtrlId].MsgCtrlIndex;

    /*************************************************/
    ret = Dcm_Uds0x23ServiceConditionCheck(ProtocolCtrlId, MsgCtrlId);
    if(E_OK != ret)
    {
     return ret;
    }
    AddressAndLengthFormatIdentifier =
            Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[1];
    /*[SWS_Dcm_00853]*/
    ret = Dcm_Uds0x23ServiceAddressAndLengthFormatIdentifierCheck(
            AddressAndLengthFormatIdentifier);
    if (E_NOT_OK == ret)
    {
        /*the processing is not successful,send NRC 0x31 */
        (void)DsdInternal_SetNrc(ProtocolCtrlId, DCM_E_REQUESTOUTOFRANGE);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    MemoryAddressSize = AddressAndLengthFormatIdentifier & 0x0Fu;
    MemoryLengthSize = (AddressAndLengthFormatIdentifier & 0xF0u) >> 4u;

    /*total length check*/
    if (((Dcm_MsgLenType)2 + MemoryAddressSize + MemoryLengthSize)
            != Dcm_MsgCtrl[MsgCtrlId].MsgContext.ReqDataLen)
    {
        /*the length of message is not correct,send NRC 0x13*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,
                DCM_E_INCORRECTMESSAGELENGTHORINVALIDFORMAT);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    /*caculate the MemoryAddress of the request message*/
    for(index = 0u;index < MemoryAddressSize;index++)
    {
        MemoryAddress = MemoryAddress << 8u;
        MemoryAddress = MemoryAddress
          | ((uint32)Dcm_MsgCtrl[MsgCtrlId].MsgContext.pReqData[2u + index]);
    }

    for(index = 0u;index < MemoryLengthSize;index++)
    {
        Memorysize = Memorysize << 8u;
        Memorysize = Memorysize
              | ((uint32)Dcm_MsgCtrl[MsgCtrlId].MsgContext.
                    pReqData[2u + MemoryAddressSize + index]);
    }
    /*MemoryAddress Range Check*/
    ret = Dcm_0x23ReadMemoryRangeCheck(MemoryAddress,
                                        Memorysize,
                                        &MemoryIdInfoIndex,
                                        &MemoryRangeInfoIndex,
                                        &MemoryAddressMatchNum);
    if((E_NOT_OK == ret) || (MemoryAddressMatchNum > 1u))
    {
        /*[SWS_Dcm_01053]different MemoryIdValue
         * compare to the request memoryAddress,send NRC 0x31*/
        /*memoryAddress is not inside the allowed memory ranges,send NRC 0x31 */
        (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_REQUESTOUTOFRANGE);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    /*MemoryAddress Security Accsess Check*/
    ret = Dcm_0x23MemoryReadSecurityCheck(MemoryIdInfoIndex,MemoryRangeInfoIndex);
    if(E_NOT_OK == ret)
    {
        /*security check not ok for requested memory interval,send NRC 0x33*/
        (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_SECURITYACCESSDENIED);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    /*[SWS_Dcm_00495]call the callout*/
    TxChannelCtrlIndex = Dcm_MsgCtrl[MsgCtrlId].Dcm_TxCtrlChannelIndex;
    TxChannelCfgIndex  = Dcm_ChannelCtrl[TxChannelCtrlIndex].Dcm_ChannelCfgIndex;
    Offset = (Dcm_DslCfg.pDcmChannelCfg)[TxChannelCfgIndex].offset;
    DCM_MemoryData = &Dcm_Channel[Offset + 1u];
    MemoryIdentifier = Dcm_DspCfg.pDcmDspMemory->
            DcmDspMemoryIdInfo[MemoryIdInfoIndex].DcmDspMemoryIdValue;

    ret = Dcm_ReadMemory(OpStatus,
                            MemoryIdentifier,
                            MemoryAddress,
                            Memorysize,
                            DCM_MemoryData,
                            ErrorCode);
    if (DCM_READ_FAILED == ret)
    {
        /*the processing is not successful,send NRC */
        (void)DsdInternal_SetNrc(ProtocolCtrlId, *ErrorCode);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }
    else if(DCM_READ_FORCE_RCRRP == ret)
    {
        /*the processing is pending,send NRC 0x78[SWS_Dcm_00839][SWS_Dcm_00840] */
        (void)DsdInternal_SetNrc(ProtocolCtrlId, DCM_E_RESPONSE_PENDING);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        Dcm_MsgCtrl[MsgCtrlId].Dcm_Ret = DCM_E_FORCE_RCRRP;
        return DCM_E_PENDING;
    }
    else if (DCM_READ_PENDING == ret)
    {
        Dcm_MsgCtrl[MsgCtrlId].Dcm_OpStatus = DCM_PENDING;
        return ret;
    }
    else
    {
        /*idle*/
    }

    /* check tx data length */
    if ((1u + Memorysize)
         > (Dcm_DslCfg.pDcmChannelCfg[TxChannelCfgIndex].Dcm_DslBufferSize))
    {
        /*Pdu length is bigger than buffer size */
        (void)DsdInternal_SetNrc(ProtocolCtrlId,DCM_E_RESPONSETOOLONG);
        DsdInternal_ProcessingDone(ProtocolCtrlId);
        return E_NOT_OK;
    }

    /**********************************************************
     * assemble positive response
     *********************************************************/
    /*the processing is successful,assemble positive response*/
    SchM_Enter_Dcm(Dcm_Channel);
    Dcm_Channel[Offset] = 0x63;             /*response SID*/
    SchM_Exit_Dcm(Dcm_Channel);
    SchM_Enter_Dcm(Dcm_MsgCtrl);
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.ResMaxDataLen = 1u + Memorysize;
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.ResDataLen    = 1u + Memorysize;
    Dcm_MsgCtrl[MsgCtrlId].MsgContext.pResData      = &Dcm_Channel[Offset];
    SchM_Exit_Dcm(Dcm_MsgCtrl);
    DsdInternal_ProcessingDone(ProtocolCtrlId);

    return ret;
}
#define DCM_STOP_SEC_CODE
#include "Dcm_MemMap.h"

#endif

